﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Configuration;
using System.Reflection;
using System.Xml;
using MusicBrowser.LibraryManagement;

using Microsoft.MediaCenter.UI;

namespace MusicBrowser
{
    [global::System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
    sealed class CommentAttribute : Attribute
    {

        // This is a positional argument
        public CommentAttribute(string comment)
        {
            Comment = comment;
        }

        public string Comment { get; private set; }

        
    }

    
    public class Config : ModelItem
    {

        /* All app settings go here, they must all have defaults or they will not work properly */
        /* They must be fields and must start with a capitol letter, and should have a default setting */
       

        public string AppVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
        public string InitialFolder = "MyMusic";
        public string Lang = "en";
        public bool TransparentBackground = false;
        public string DefaultView = "List";

        /* End of app specific settings*/

       
        [MarkupVisible]

        public bool TransparentBackgroundMCML
        {
            get 
            {
                return TransparentBackground; 
            }
        }


        private static object _syncobj = new object(); 
        private static Config _instance = null; 
        public static Config Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_syncobj)
                    {
                        if (_instance == null)
                        {
                            _instance = new Config();
                        }
                    }
                }
                return _instance;
            }
        }

        public string filename;

        private Dictionary<string, object> defaults = new Dictionary<string, object>();
        public ArrayListDataSet initialFolders = new ArrayListDataSet();

        private Config ()
	    {

            // store the defaults so we can later recover them if needed
            foreach (FieldInfo field in SettingFields)
            {
                defaults[field.Name] = field.GetValue(this);  
            }

            var path = Helper.AppConfigPath;
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path); 
            }

            filename = Path.Combine(path, "MusicBrowser.config");
            try
            {
                Read(); 
            }
            catch
            {
                //File.WriteAllText(filename, "<Settings></Settings>");
                
                //Write();
            }
            initialFolders = BuildInitialFolders();
	    }

        public ArrayListDataSet BuildInitialFolders()
        {
            ArrayListDataSet IF = new ArrayListDataSet();
            if (InitialFolder.ToLower() == Path.Combine(Helper.AppConfigPath, "VirtualFolder.vf").ToLower())
            {
                foreach (var line in File.ReadAllLines(InitialFolder))
                {
                    if (line.StartsWith("folder:"))
                    {
                        if (line.Substring(7).Trim().ToLower() == "mymusic") IF.Add("MyMusic");
                        else IF.Add(line.Substring(7).Trim());
                    }
                }

            }
            else if (InitialFolder.ToLower() == "mymusic") IF.Add("MyMusic");
            else IF.Add(InitialFolder);

            return IF;

        }

        private List<FieldInfo> SettingFields
        {
            get
            {
                // todo: cache this, not really important 
                List<FieldInfo> fields = new List<FieldInfo>();
                foreach (MemberInfo mi in this.GetType().GetMembers(
                       BindingFlags.Public | BindingFlags.Instance ))
                {
                    if (IsSettingField(mi))
                    {
                        fields.Add((FieldInfo)mi); 
                    }
                }
                return fields;
            }
        }

        /// <summary>
        /// Read current config from file
        /// </summary>
        public void Read()
        {
            bool stuff_changed = false;

            XmlDocument dom = new XmlDocument();
            dom.Load(filename);

            foreach (FieldInfo field in SettingFields)
            {

                var settingsNode = GetSettingsNode(dom);

                XmlNode node = settingsNode.SelectSingleNode(field.Name);

                if (node == null)
                {
                    node = dom.CreateNode(XmlNodeType.Element, field.Name, null);
                    settingsNode.AppendChild(node);
                    node.InnerText = Default(field).ToString();
                    stuff_changed = true;
                }

               
                string value = node.InnerText;

                if (field.FieldType == typeof(string))
                {
                    field.SetValue(this, value); 
                }
                else if (field.FieldType == typeof(bool))
                {
                    try
                    {
                        field.SetValue(this, bool.Parse(value));
                    }
                    catch
                    {
                        field.SetValue(this, Default(field));
                        stuff_changed = true;
                    }
                }
                else 
                {
                    // only supporting above types for now
                    return;
                }
            }

            if (stuff_changed)
            {
                try { Directory.Delete(Helper.AppConfigPath, true); }
                catch { }
                Directory.CreateDirectory(Helper.AppConfigPath);
                File.WriteAllText(filename, "<Settings></Settings>");
                Write();
            }
      }


        private static XmlNode GetSettingsNode(XmlDocument dom)
        {
            return dom.SelectSingleNode("/Settings");
        }



        /// <summary>
        /// Write current config to file
        /// </summary>
        public void Write()
        {

            XmlDocument dom = new XmlDocument();
            dom.Load(filename); 

            foreach (FieldInfo field in SettingFields)
            {

                string value = "";
                object v = field.GetValue(this);
                if (v == null)
                {
                    v = Default(field);
                }
                if (v != null)
                {
                    value = v.ToString();
                }

                var settingsNode = GetSettingsNode(dom);

                XmlNode node = settingsNode.SelectSingleNode(field.Name);

                if (node == null)
                {
                    node = dom.CreateNode(XmlNodeType.Element,field.Name, null);
                    settingsNode.AppendChild(node);
                }
                node.InnerText = value;
            } // for each
            dom.Save(filename);
        }


        private static bool IsSettingField(MemberInfo mi)
        {
            return mi.Name[0].ToString() != mi.Name[0].ToString().ToLower() && mi.MemberType == MemberTypes.Field;
        }

        private object Default(MemberInfo field)
        {
            //TODO: some nice error handling
            // DefaultAttribute da = (DefaultAttribute)field.GetCustomAttributes(typeof(DefaultAttribute), false)[0];
            return defaults[field.Name];
        }


    }
}
